#include <vector>
#include <fstream>
#include <assert.h>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include <errno.h>
#include "memalloc.h"
#include "memalloc.hpp"

using std::vector;
vector<size_t> ids_;

int ma_init(size_t mem, size_t swap, const char* swap_path) {
	try { 
		MemAlloc::Init(mem, swap, swap_path); 
		ids_.clear();
		return 1;
	} catch(MemAllocException& e) {
		fprintf(stderr, "%s\n", e.what());
		if (e.GetErrorCode() == MemAllocException::E_ALREADY) {
			errno = EALREADY;
			return 0;
		}
		exit(-1);
	} catch(std::bad_alloc& e) {
		fprintf(stderr, "%s\n", e.what());
		errno = ENOMEM;
		return 0;
	} catch(std::ios_base::failure& e) {
		fprintf(stderr, "%s\n", e.what());
		errno = EACCES;
		return 0;
	} catch(...) {
		fprintf(stderr, "Unknown std::exception\n");
		exit(-1);
	}
}

void ma_deinit() {
	try {
		MemAlloc::Deinit();
		for (auto i : ids_) {
			delete (SmartPtr<char>*)i;
		}
	}
	catch(std::exception& e) {
		fprintf(stderr, "%s\n", e.what());
		exit(-1);
	} catch(...) {
		fprintf(stderr, "Unknown std::exception\n");
		exit(-1);
	}
	
}

size_t ma_alloc(size_t sz) {
	try {
		SmartPtr<char> sp = MemAlloc::Instance().Alloc<char>(sz);
		SmartPtr<char> *sp_id = new SmartPtr<char>(sp); 
		size_t id = (size_t) sp_id;
		assert(std::find(ids_.begin(), ids_.end(), id) == ids_.end());
		ids_.push_back(id);
		return id;
	} catch(MemAllocException& e) {
		fprintf(stderr, "%s\n", e.what());
		MemAllocException::ErrorCode code = e.GetErrorCode();
		if (code == MemAllocException::E_NOMEM)
			errno = ENOMEM;
		else if (code == MemAllocException::E_2BIG)
			errno = E2BIG;
		else if (code == MemAllocException::E_MLINK)
			errno = EMLINK;
		else
			exit(-1);
		return 0;
	} catch(std::exception& e) {
		fprintf(stderr, "%s\n", e.what());
		exit(-1);
	} catch(...) {
		fprintf(stderr, "Unknown std::exception\n");
		exit(-1);
	}
}

int ma_free(size_t id) {
	try {
		if (std::find(ids_.begin(), ids_.end(), id) == ids_.end()) {
			errno = EFAULT;
			return 0;
		}
		SmartPtr<char> *sp_id = (SmartPtr<char>*) id;
		MemAlloc::Instance().Free(*sp_id);
		delete sp_id;
		return 1;
	} catch(std::exception& e) {
		fprintf(stderr, "%s\n", e.what());
		exit(-1);
	} catch(...) {
		fprintf(stderr, "Unknown std::exception\n");
		exit(-1);
	}
}

void* ma_get(size_t id) {
	try {
		if (std::find(ids_.begin(), ids_.end(), id) == ids_.end()) {
			errno = EFAULT;
			return 0;
		}
		SmartPtr<char> *sp_id = (SmartPtr<char>*) id;
		return sp_id->Get();	
	} catch(MemAllocException& e) {
		fprintf(stderr, "%s\n", e.what());
		MemAllocException::ErrorCode code = e.GetErrorCode();
		if (code == MemAllocException::E_NOMEM)
			errno = ENOMEM;
		else if (code == MemAllocException::E_NOBUFS)
			errno = ENOBUFS;
		else
			exit(-1);
		return 0;
	} catch(std::ios_base::failure& e) {
		fprintf(stderr, "%s\n", e.what());
		errno = EBADF;
		return 0;
	} catch(std::exception& e) {
		fprintf(stderr, "%s\n", e.what());
		exit(-1);
	} catch(...) {
		fprintf(stderr, "Unknown std::exception\n");
		exit(-1);
	}
}

int ma_release(size_t id) {
	try {
		if (std::find(ids_.begin(), ids_.end(), id) == ids_.end()) {
			errno = EFAULT;
			return 0;
		}
		SmartPtr<char> *sp_id = (SmartPtr<char>*) id;
		sp_id->Release();	
		return 1;
	} catch(std::exception& e) {
		fprintf(stderr, "%s\n", e.what());
		exit(-1);
	} catch(...) {
		fprintf(stderr, "Unknown std::exception\n");
		exit(-1);
	}
}

